package main

import (
	"fmt"
	"net"
	"net/http"
	"strconv"

	"gitee.com/jn-shao/common"
	"github.com/afex/hystrix-go/hystrix"
	grpcServer "github.com/asim/go-micro/plugins/server/grpc/v3"
	ratelimit "github.com/asim/go-micro/plugins/wrapper/ratelimiter/uber/v3"
	opentracing2 "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
	"github.com/asim/go-micro/v3"
	"github.com/asim/go-micro/v3/registry"
	"github.com/asim/go-micro/v3/server"
	"github.com/go-micro/plugins/v3/registry/consul"
	"github.com/opentracing/opentracing-go"

	"svcSrv/domain/repository"
	service2 "svcSrv/domain/service"
	"svcSrv/global"
	"svcSrv/handler"
	"svcSrv/initialize"
	hystrix2 "svcSrv/plugin/hystrix"
	"svcSrv/proto/svcSrv"
)

func main() {

	//region 1.配置中心，存放经常变动的变量
	initialize.InitConfig()
	//endregion

	//region 2.注册中心
	consul := consul.NewRegistry(func(options *registry.Options) {
		options.Addrs = []string{
			global.ServerConfig.ConsulInfo.Host + ":" +
				strconv.FormatUint(global.ServerConfig.ConsulInfo.Port, 10),
		}
	})
	//endregion

	//region 3.使用配置中心连接 mysql
	initialize.InitDB()
	//endregion

	//region 4.添加链路追踪
	t, io, err := common.NewTracer(global.ServerConfig.JaegerInfo.ServiceName,
		global.ServerConfig.JaegerInfo.Host+":"+strconv.FormatUint(global.ServerConfig.JaegerInfo.Port, 10))
	if err != nil {
		common.Error(err)
	}
	defer io.Close()
	opentracing.SetGlobalTracer(t)
	//endregion

	//region 5.添加熔断器，作为客户端需要启用，服务端不需要
	hystrixStreamHandler := hystrix.NewStreamHandler()
	hystrix.ConfigureCommand(global.ServerConfig.HystrixInfo.Name, hystrix.CommandConfig{Timeout: 1000})
	hystrixStreamHandler.Start()

	//启动熔断监听程序，供hystrix服务采集信息
	go func() {
		//http://192.168.0.121:9092/turbine/turbine.stream
		//熔断器看板访问地址 http://127.0.0.1:9002/hystrix，url后面一定要带 /hystrix
		//0.0.0.0本机地址，监听熔断器面板地址
		err = http.ListenAndServe(net.JoinHostPort("0.0.0.0",
			strconv.FormatUint(global.ServerConfig.HystrixInfo.Port, 10)), hystrixStreamHandler)
		if err != nil {
			common.Error(err)
		}
	}()
	//endregion

	//region 6.添加日志中心
	//1）需要程序日志打入到日志文件中
	//2）在程序中添加filebeat.yml 文件
	//3) 启动filebeat，启动命令 ./filebeat -e -c filebeat.yml
	fmt.Println("日志统一记录在根目录 micro.log 文件中，请点击查看日志！")
	//endregion

	//region 7.添加监控，供prometheus采集信息
	common.PrometheusBoot(int(global.ServerConfig.PrometheusInfo.Port))
	//endregion

	//region 8.创建k8s连接
	initialize.InitClientset()
	//endregion

	//region 9.创建服务
	service := micro.NewService(
		//开启grpc server，自定义服务地址，且必须写在其它参数前面
		micro.Server(grpcServer.NewServer(func(options *server.Options) {
			options.Advertise = global.ServerConfig.Host + ":" +
				strconv.FormatUint(global.ServerConfig.Port, 10)
		})),
		micro.Name(global.ServerConfig.Name),
		micro.Version("latest"),
		//指定服务端口
		micro.Address(":"+strconv.FormatUint(global.ServerConfig.Port, 10)),

		//添加注册中心
		micro.Registry(consul),
		micro.RegisterTTL(5),
		micro.RegisterInterval(5),

		//添加链路追踪
		//服务端
		micro.WrapHandler(opentracing2.NewHandlerWrapper(opentracing.GlobalTracer())),
		//客户端
		micro.WrapClient(opentracing2.NewClientWrapper(opentracing.GlobalTracer())),

		//添加熔断，只作为客户端的时候起作用，如果存在调用别人的情况，原则上不去主动调用
		micro.WrapClient(hystrix2.NewClientHystrixWrapper()),
		//添加限流
		micro.WrapHandler(ratelimit.NewHandlerWrapper(1000)),
	)
	//初始化服务
	service.Init()

	//只能执行一遍，初始化数据表
	//err = repository.NewSvcRepository(db).InitTable()
	//if err != nil {
	//	common.Fatal(err)
	//}

	// 注册句柄，可以快速操作已开发的服务
	SvcDataService := service2.NewSvcDataService(repository.NewSvcRepository(global.DB), global.Clientset)
	svcSrv.RegisterSvcHandler(service.Server(), &handler.SvcHandler{SvcDataService: SvcDataService})

	// 启动服务
	if err := service.Run(); err != nil {
		//输出启动失败信息
		common.Fatal(err)
	}
	//endregion
}
